package com.battle.service.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.battle.pojo.entity.Exam;
import com.battle.pojo.entity.ExamStudy;
import com.battle.pojo.entity.ExamStudyDetails;
import com.battle.pojo.entity.QuestionBankDetails;
import com.battle.pojo.param.exam.CreateAppointQuestionParam;
import com.battle.pojo.param.exam.CreateRandomQuestionParam;
import com.battle.pojo.param.examStudy.*;
import com.battle.pojo.param.examStudyDetails.CreateExamStudyDetailsParam;
import com.battle.pojo.vo.examStudy.*;
import com.battle.pojo.dto.examStudy.*;
import com.battle.pojo.vo.examStudyDetails.GetExamStudyDetailsListVo;
import com.battle.pojo.vo.examStudyDetails.GetExamStudyDetailsVo;
import com.battle.service.repository.in.*;
import com.battle.service.service.in.ExamStudyService;
import com.google.gson.Gson;
import nirvana.core.domains.vo.PageResult;
import nirvana.core.exceptions.BizException;
import nirvana.core.utils.ids.IdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindException;


import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 【描 述】：用户考试管理服务
 * 【环 境】：J2SE 17
 * 【详 细】：
 */
@Service
public class ExamStudyServiceImpl implements ExamStudyService {

    private final ExamStudyRepository examStudyRepository;
    private final ExamRepository examRepository;
    private final ExamStudyDetailsRepository examStudyDetailsRepository;
    private final QuestionBankRepository bankRepository;
    private final QuestionBankDetailsRepository bankDetailsRepository;

    public ExamStudyServiceImpl(ExamStudyRepository examStudyRepository, ExamRepository examRepository, ExamStudyDetailsRepository examStudyDetailsRepository, QuestionBankRepository bankRepository, QuestionBankDetailsRepository bankDetailsRepository) {
        this.examStudyRepository = examStudyRepository;
        this.examRepository = examRepository;
        this.examStudyDetailsRepository = examStudyDetailsRepository;
        this.bankRepository = bankRepository;
        this.bankDetailsRepository = bankDetailsRepository;
    }


    /**
     * 创建用户考试管理
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long  createExamStudy(CreateExamStudyParam param) {
        Gson gson = new Gson();

        //根据用户id和试卷id查找未完成的考试
        List<ExamStudy> examStudies = examStudyRepository.getBaseMapper().selectList(
                new LambdaQueryWrapper<>(ExamStudy.class)
                        .eq(ExamStudy::getUserId, param.getUserId())
                        .eq(ExamStudy::getExamId, param.getExamId())
                        .eq(ExamStudy::getExamStatus, 0));
        if (CollectionUtil.isNotEmpty(examStudies)){
            GetExamStudyVo examStudy = getExamStudy(examStudies.get(0).getId());
            return examStudy.getExamStudyId();
        }

        List<GetExamStudyDetailsVo> detailsVoList = new ArrayList<>();

        ExamStudy examStudy = new ExamStudy();
        BeanUtils.copyProperties(param, examStudy);
        Long id = IdGenerator.SNOW.generate();
        examStudy.setId(id);

        Exam exam = examRepository.getByIdCheck(param.getExamId());
        examStudy.setExamId(exam.getId());
        examStudy.setExamStartTime(exam.getStartTime());
        examStudy.setExamStatus(0);
        examStudy.setExamScore(BigDecimal.ZERO);

        //用户需要考试的题目信息
        List<CreateExamStudyDetailsParam> examStudyParams=getExamStudyDetailsList(exam);

        BigDecimal totalScore=BigDecimal.ZERO;
        if (CollectionUtil.isNotEmpty(examStudyParams)){
            List<ExamStudyDetails> detailsList=new ArrayList<>();
            for (CreateExamStudyDetailsParam detailsParam : examStudyParams) {
                ExamStudyDetails details = new ExamStudyDetails();
                BeanUtils.copyProperties(detailsParam, details);
                details.setExamStudyId(id);
                details.setUserId(examStudy.getUserId());
                details.setExamStudyId(examStudy.getId());
                details.setExamId(examStudy.getExamId());
                details.setStatus(0);
                details.setId(IdGenerator.SNOW.generate());
                detailsList.add(details);

                GetExamStudyDetailsVo detailsVo = new GetExamStudyDetailsVo();
                BeanUtils.copyProperties(details, detailsVo);

                List<String> bankAnswerJson = JSONArray.parseArray(details.getBankAnswer(),String.class);
                Map<String,String> optionJson = gson.fromJson(details.getOptions(), Map.class);
                detailsVo.setBankAnswerJson(bankAnswerJson);
                detailsVo.setOptionsJson(optionJson);

                detailsVoList.add(detailsVo);

                totalScore=totalScore.add(details.getScore());
            }
            if(!examStudyDetailsRepository.saveBatch(detailsList)){
                throw new BizException("创建用户考试详情失败");
            }
        }

        examStudy.setTotalScore(totalScore);
        examStudy.setNeedFinishQuestionNum(examStudyParams.size());
        examStudyRepository.create(examStudy);
        return examStudy.getId();
    }

    List<CreateExamStudyDetailsParam> getExamStudyDetailsList(Exam exam){
        List<CreateExamStudyDetailsParam> examStudyParams=new ArrayList<>();

        //如果是随机题目
        if (exam.getIsRandomQuestion()){
            //拿到题库ids
            List<Long> bankIds = JSONArray.parseArray(exam.getQuestionBankIds(), Long.class);
            if (!JSONUtil.isJsonArray(exam.getRandomQuestionJson())) {
                throw new BizException("随机题目json格式错误");
            }
            List<CreateRandomQuestionParam> randomQuestionList = JSONUtil.toList(exam.getRandomQuestionJson(), CreateRandomQuestionParam.class);
            for (CreateRandomQuestionParam randomQuestionParam : randomQuestionList) {
                List<QuestionBankDetails> list = bankDetailsRepository.getListByBankId(bankIds, randomQuestionParam.getType(), randomQuestionParam.getNumber());
                for (QuestionBankDetails questionBankDetails : list) {
                    //添加到用户需要学习的题目
                    CreateExamStudyDetailsParam examStudyParam = new CreateExamStudyDetailsParam();
                    BeanUtils.copyProperties(questionBankDetails, examStudyParam);
                    examStudyParam.setQuestionId(questionBankDetails.getId());
                    examStudyParam.setBankAnswer(questionBankDetails.getAnswer());
                    examStudyParam.setScore(randomQuestionParam.getScore());
                    examStudyParams.add(examStudyParam);
                }
            }
        }else{
            //如果是指定题目
            List<CreateAppointQuestionParam> appointQuestionList = JSONUtil.toList(exam.getAppointQuestionJson(), CreateAppointQuestionParam.class);
            List<Long> questionIdList = appointQuestionList.stream().map(CreateAppointQuestionParam::getQuestionId).distinct().collect(Collectors.toList());
            List<QuestionBankDetails> list = bankDetailsRepository.getMap(questionIdList).values().stream().collect(Collectors.toList());
            for (QuestionBankDetails questionBankDetails : list) {
                //添加到用户需要学习的题目
                CreateExamStudyDetailsParam examStudyParam = new CreateExamStudyDetailsParam();
                BeanUtils.copyProperties(questionBankDetails, examStudyParam);
                examStudyParam.setQuestionId(questionBankDetails.getId());
                examStudyParam.setBankAnswer(questionBankDetails.getAnswer());

                examStudyParam.setScore(appointQuestionList.stream().filter(e -> e.getQuestionId().equals(questionBankDetails.getId())).findFirst().get().getScore());
                examStudyParams.add(examStudyParam);
            }
        }
        return examStudyParams;
    }

    /**
     * 修改用户考试管理
     *
     * @param param
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editExamStudy(EditExamStudyParam param) {
        Long id = param.getId();
        ExamStudy examStudy = examStudyRepository.getByIdCheck(param.getExamStudyId());

        int finishQuestionNum=0;
        BigDecimal examScore=BigDecimal.ZERO;

        //根据唯一id查询用户考试题目详情
        List<ExamStudyDetails> detailsList = examStudyDetailsRepository.selectExamStudyDetailsByExamStudyId(param.getExamStudyId());
        for (ExamStudyDetails studyDetails : detailsList) {

            if (id.equals(studyDetails.getId())) {
                studyDetails.setStatus(1);
                String userAnswer = JSONArray.toJSONString(param.getUserAnswer());
                studyDetails.setUserAnswer(userAnswer);
                //计算是否回答正确
                Boolean equalsAnswer = equalsAnswer(param.getUserAnswer(), studyDetails.getBankAnswer());
                studyDetails.setIsCorrect(equalsAnswer);
                if (!examStudyDetailsRepository.edit(studyDetails)){
                    throw new BizException("修改用户考试详情失败");
                }
            }

            //如果是已经完成的题目
            if (studyDetails.getStatus() == 1) {
                finishQuestionNum++;
                if (studyDetails.getIsCorrect()) {
                    examScore = examScore.add(studyDetails.getScore());
                }
            }
        }

        examStudy.setExamScore(examScore);
        examStudy.setExamStatus(finishQuestionNum == detailsList.size() ? 1 : 0);
        if (finishQuestionNum == detailsList.size()){
            examStudy.setExamEndTime(LocalDateTime.now());
            //计算考试时长多少分钟
            long minutes = examStudy.getExamStartTime().until(examStudy.getExamEndTime(), java.time.temporal.ChronoUnit.MINUTES);
            examStudy.setExamDuration(BigDecimal.valueOf(minutes));
        }
        examStudy.setFinishQuestionNum(finishQuestionNum);
        examStudyRepository.edit(examStudy);
    }

    Boolean equalsAnswer(List<String> userAnswer, String answer) {
        //1.将两边答案转换成数组
        List<String> answerList = JSONArray.parseArray(answer, String.class);
        //2.将两边答案排序
        userAnswer.sort(String::compareTo);
        answerList.sort(String::compareTo);
        //3.比较两边答案是否一致
        return userAnswer.equals(answerList);
    }
    /**
     * 移除用户考试管理
     *
     * @param id
     */
    @Override
    public void removeExamStudy(Long id) {
        examStudyRepository.removeById(id);
    }

    /**
     * 启动/禁用用户考试管理
     *
     * @param id
     */
    @Override
    public void enabledExamStudy(Long id) {
        ExamStudy examStudy = examStudyRepository.getByIdCheck(id);
        examStudy.setIsDisable(!examStudy.getIsDisable());
        examStudyRepository.edit(examStudy);
    }

    /**
     * 获取用户考试管理详情
     *
     * @param id
     * @return
     */
    @Override
    public GetExamStudyVo getExamStudy(Long id) {
        ExamStudy examStudy = examStudyRepository.getByIdCheck(id);
        GetExamStudyVo vo = new GetExamStudyVo();
        BeanUtils.copyProperties(examStudy, vo);
        vo.setExamStudyId(examStudy.getId());

        //完整的题目情况
        List<GetExamStudyDetailsVo> detailsVoList=new ArrayList<>();
        //题目状态
        List<GetExamStudyDetailsListVo> statusList=new ArrayList<>();

        //根据用户考试id查询详情
        List<ExamStudyDetails> detailsList = examStudyDetailsRepository.selectExamStudyDetailsByExamStudyId(id);
        for (ExamStudyDetails studyDetails : detailsList) {
            GetExamStudyDetailsVo detailsVo = new GetExamStudyDetailsVo();
            BeanUtils.copyProperties(studyDetails, detailsVo);

            List<String> bankAnswerJson = JSONArray.parseArray(studyDetails.getBankAnswer(),String.class);
            Map<String,String> optionJson = new Gson().fromJson(studyDetails.getOptions(), Map.class);

            detailsVo.setBankAnswerJson(bankAnswerJson);
            detailsVo.setOptionsJson(optionJson);
            detailsVoList.add(detailsVo);

            GetExamStudyDetailsListVo statusVo = new GetExamStudyDetailsListVo();
            statusVo.setId(studyDetails.getId());
            //判断题目是否正确
            if (studyDetails.getStatus() == 0) {
                statusVo.setStatus(2);
            } else {
                statusVo.setStatus(studyDetails.getIsCorrect() ? 0 : 1);
            }
            statusList.add(statusVo);
        }
        vo.setStatusList(statusList);
        vo.setDetailsVoList(detailsVoList);
        return vo;
    }

    /**
     * 根据id获取题目详情
     * @param id
     * @return
     */
    @Override
    public GetExamStudyDetailsVo getExamStudyDetails(Long id) {
        GetExamStudyDetailsVo vo=new GetExamStudyDetailsVo();
        ExamStudyDetails details = examStudyDetailsRepository.getByIdCheck(id);
        BeanUtils.copyProperties(details, vo);

        List<String> bankAnswerJson = JSONArray.parseArray(details.getBankAnswer(),String.class);
        Map<String,String> optionJson = new Gson().fromJson(details.getOptions(), Map.class);

        vo.setBankAnswerJson(bankAnswerJson);
        vo.setOptionsJson(optionJson);

        return vo;
    }

    /**
     * 根据试卷id和用户id获取试卷详情
     * @param examId
     * @return
     */
    @Override
    public GetExamDetailsVo getExamDetails(Long examId, Long userId) {
        Exam exam = examRepository.getByIdCheck(examId);
        GetExamDetailsVo vo = new GetExamDetailsVo();
        BeanUtils.copyProperties(exam, vo);
        vo.setExamId(examId);
        vo.setExamName(exam.getName());
        vo.setUserId(userId);

        List<CreateExamStudyDetailsParam> examStudyDetailsList = getExamStudyDetailsList(exam);
        //题目数量
        vo.setQuestionCount(examStudyDetailsList.size());
        //题目总分
        BigDecimal totalScore = BigDecimal.ZERO;
        for (CreateExamStudyDetailsParam examStudyDetails : examStudyDetailsList) {
            totalScore = totalScore.add(examStudyDetails.getScore());
        }
        vo.setTotalScore(totalScore);
        //提交次数
        List<ExamStudy> examStudies = examStudyRepository.getBaseMapper().selectList(
                new LambdaQueryWrapper<>(ExamStudy.class)
                        .eq(ExamStudy::getUserId, userId)
                        .eq(ExamStudy::getExamId, examId)
                        .eq(ExamStudy::getIsDelete,false));
        if (CollectionUtil.isNotEmpty(examStudies)) {
            vo.setSubmitCount(examStudies.size());
        }else{
            vo.setSubmitCount(0);
        }
        return vo;
    }

    /**
     * 获取用户考试管理 列表
     *
     * @param param
     * @return
     */
    @Override
    public PageResult<GetExamStudyListVo> getExamStudyList(GetExamStudyListParam param) {

        SelectExamStudyDto dto = new SelectExamStudyDto();
        BeanUtils.copyProperties(param, dto);
        Page<ExamStudy> page = examStudyRepository.selectExamStudy(dto);
        List<ExamStudy> examStudyList = page.getRecords();
        List<GetExamStudyListVo> list = new ArrayList<>();

        if (CollectionUtil.isNotEmpty(examStudyList)){
            for (ExamStudy examStudy : examStudyList) {
                GetExamStudyListVo vo = new GetExamStudyListVo();
                BeanUtils.copyProperties(examStudy, vo);
                Exam exam = examRepository.getById(examStudy.getExamId());
                if (exam!=null){
                    vo.setExamName(exam.getName());
                }
                vo.setExamStudyId(examStudy.getId());
                list.add(vo);
            }
        }
        return new PageResult<>(list, page);

    }

    /**
     * 获取用户考试管理下拉列表
     *
     * @param param
     * @return
     */
    @Override
    public List<GetExamStudyDownListVo> getExamStudyDownList(GetExamStudyDownListParam param) {
        ExamStudy po = new ExamStudy();
        if (param != null) {
            BeanUtils.copyProperties(param, po);
        }
        List<ExamStudy> examStudyList = examStudyRepository.getListByEntity(po);

        List<GetExamStudyDownListVo> list = new ArrayList<>();
        for (ExamStudy examStudy : examStudyList) {
            GetExamStudyDownListVo vo = new GetExamStudyDownListVo();
            BeanUtils.copyProperties(examStudy, vo);
            list.add(vo);
        }
        return list;
    }


}



